/** ***********************************************************************************
* @file         log_task.c
* @brief        系统日志管理任务
* @details      主要使用来处理系统日志管理，提供日志接口
* @author       杨小珛
* @date         2020/12/24
* @copyright    北京高知科技有限公司    
* @version      V1.0
* @attention    无
**************************************************************************************/
#include "log_task.h"
#include "mon_task.h"
#include "rtc_task.h"
#include "com_lib.h"
#include "flash_buffer.h"
#include "flash_config.h"

GaozMutexHandle_t   log_info_mutex = 0;                 //数据互斥
GaozQueueHandle_t   log_debug_queue = 0;
GaozMutexHandle_t   log_error_mutex = 0;                 //数据互斥

#define LOG_TASK_ENABLE ( 0 )
#define LOG_TASK_NAME "LOG_TASK"

static debug_msg_typedef log_debug_msg_s;
static log_error_code_t log_error_code;

static void  sys_log_task( void * pvParameters); 

#if( LOG_TASK_ENABLE == 1 )
static void log_queue_create(void);
static uint32_t log_queue_get(debug_msg_typedef *msg);
#endif

static uint8_t log_debug_head_infor(log_print_mode_enum mode ,char * name);
static uint32_t log_parse_error_code( uint8_t *data , uint16_t len ,uint16_t *err );
static uint32_t log_error_code_list_write( uint16_t err );
static void log_error_code_flash_read( void );

/** ****************************************************************************
* @remarks       void log_create_task( unsigned portBASE_TYPE uxPriority )
* @brief         创建系统日志管理任务
* @param[in]     uxPriority 优先级
* @param[out]    无
* @return        无
* @attention     在系统启动后进行创建
*******************************************************************************/
void log_create_task( unsigned portBASE_TYPE uxPriority )
{
    memset((uint8_t *)&log_debug_msg_s , 0x00 , sizeof(debug_msg_typedef));
    log_info_mutex = gaoz_mutex_create();/*创建系统日志互斥体*/
    if(log_info_mutex == 0)
    {
        while(1); /*创建信号量失败*/
    }
    log_error_mutex = gaoz_mutex_create();/*创建系统日志互斥体*/
    if( log_error_mutex == 0 )
    {
        while(1); /*创建信号量失败*/ 
    }
    log_error_code.num = 0;
    /*计算申请系统的空间长度*/
    log_error_code.len = SYS_ERR_LIST_NUM;
    /*创建错误代码列表*/
    log_error_code.id = ( uint8_t * )gaoz_fibo_malloc( log_error_code.len );
    if( log_error_code.id == NULL )
    {
        while(1); /*创建失败*/
    }
    memset( (uint8_t *)log_error_code.id , 0, log_error_code.len );
    /*创建错误时间列表*/
    log_error_code.time = ( uint32_t *)gaoz_fibo_malloc( SYS_ERR_LIST_NUM * sizeof( uint32_t ) );
    if( log_error_code.time == NULL )
    {
        while(1); /*创建失败*/
    }
    memset( (uint8_t *)log_error_code.time , 0, SYS_ERR_LIST_NUM * sizeof( uint32_t ) );
    log_error_code_flash_read();
#if( LOG_TASK_ENABLE == 1 )
    log_queue_create(); /*创建日志消息队列*/
#endif
    gaoz_thread_create(sys_log_task, LOG_TASK_NAME, 1024*2, NULL, OSI_PRIORITY_LOW);
}

#if( LOG_TASK_ENABLE == 1 )
/** ****************************************************************************
* @remarks       static void log_queue_create(void)
* @brief         创建日志数据接收消息队列
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void log_queue_create(void)
{
    log_debug_queue = gaoz_queue_create(DEBUG_UART_TX_QUEUE_MAX_NUM, sizeof(debug_msg_typedef));
    if(log_debug_queue == 0)
    {
        while(1); /*创建消息队列失败*/
    }
}
/** ****************************************************************************
* @remarks       static uint32_t log_queue_get(debug_msg_typedef *msg)
* @brief         获取系统日志消息队列数据
* @param[in]     无
* @param[out]    *msg 消息队列目标地址
* @return        pdPASS 获取数据成功 ， pdFAIL 获取数据失败
* @attention     无
*******************************************************************************/
static uint32_t log_queue_get(debug_msg_typedef *msg)
{
    if(log_debug_queue == 0)
    {
        log_queue_create(); 
    }
    if( gaoz_queue_get( log_debug_queue, msg, MSG_LOG_SAM_REV_WAIT_TIME) == 0 )
    {
        return pdPASS;
    }
    else
    {
        return pdFAIL;
    }
}
#endif
/** ****************************************************************************
* @remarks       static uint8_t log_debug_head_infor(log_print_mode_enum mode ,char * name)
* @brief         添加系统日志打印消息头
* @param[in]     mode 打印日志的模式
* @param[in]     * name 打印日志的任务名称
* @param[out]    无
* @return        消息头数据长度
* @attention     无
*******************************************************************************/
static uint8_t log_debug_head_infor(log_print_mode_enum mode ,char * name)
{
    uint8_t  name_len = 0 ;
    uint8_t  total_len = 0;
	uint8_t	 rtc_time[30] = {0};
	uint8_t  time_len = 0 ;
    if( mode < DEFAULE_MODE )
    {
        //memcpy(( uint8_t * )&log_debug_msg_s.pData[0],"[GAOZ_LOG]",10);
        //total_len += 10;
        log_debug_msg_s.pData[total_len] = '[';
        total_len += 1;
        rtc_sys_get( RTC_TIM_STRING , (void *)rtc_time );
        time_len = strnlen((const char *)rtc_time,sizeof(rtc_time));
        memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],rtc_time,time_len);
        total_len += time_len;
        log_debug_msg_s.pData[total_len] = ']';
        total_len += 1;
        if( mode == DEBUG_MODE )
        {
            memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],"[DEBUG]",7);
            total_len += 7;
        }
        else if( mode == INFOR_MODE )
        {
            memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],"[INFOR]",7);
            total_len += 7;
        }
        else if( mode == ERROR_MODE )
        {
            memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],"[ERROR]",7);
            total_len += 7;
        }
        /*获取不到任务名称时，则认为不是在任务中进行打印*/
        if( name != NULL ) 
        {
            memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],"[",1);
            total_len += 1;
            name_len = strnlen((const char *)name,64 );
            memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],name,name_len);
            total_len += name_len;
            memcpy(( uint8_t * )&log_debug_msg_s.pData[total_len],"]",1);
            total_len += 1;
        }
    }
    return total_len;
}

/** ****************************************************************************
* @remarks       uint32_t log_debug_send( log_print_mode_enum mode ,char *name ,void * pbuf, uint16_t dlen )
* @brief         添加系统日志打印消息头
* @param[in]     mode 打印日志的模式
* @param[in]     * name 打印日志的任务名称
* @param[in]     * pbuf 打印数据源地址
* @param[in]     dlen 打印数据的长度
* @param[out]    无
* @return        pdPASS 数据发送成功 ， pdFAIL 数据发送失败
* @attention     函数的功能是将打印的数据前装到消息队列中，发送发送给任务进行数据发送
*******************************************************************************/
uint32_t log_debug_send( log_print_mode_enum mode ,char *name ,void * pbuf, uint16_t dlen )
{
    uint32_t  osR = 0;
    uint32_t  len = 0;
    uint32_t  res = pdFAIL;
    uint8_t   head_len = 0;
    uint16_t err_code;

    if(pbuf == NULL)
    {
        return pdFAIL;
    }
    /*添加信息打印头*/
    if( log_info_mutex != 0 )
    {
        gaoz_mutex_lock( log_info_mutex );
        osR = 1;
    }
    /*清空日志缓存空间数据*/
    memset( log_debug_msg_s.pData , 0x00 ,DEBUG_UART_TX_QUEUE_LEN );
    if( mode != DEFAULE_MODE )
    {
        head_len = log_debug_head_infor( mode , name );
    }
    if(dlen == 0)
    {
        len = strnlen((const char *)pbuf,( DEBUG_UART_TX_QUEUE_LEN - head_len ) );
    }
    else
    {
        len = dlen;
    }
    if( len > ( DEBUG_UART_TX_QUEUE_LEN - head_len ) )
    {
        len = DEBUG_UART_TX_QUEUE_LEN - head_len;
    }
    log_debug_msg_s.DataLen  = ( len + head_len );
    memcpy(( uint8_t * )&log_debug_msg_s.pData[head_len],pbuf,len);
#if( LOG_TASK_ENABLE == 1 )
    if( log_debug_queue != 0 )
    {
        res = gaoz_queue_put(log_debug_queue,&log_debug_msg_s,DEBUG_UART_TX_DATA_TIME);
        if( res == 0 )
        {
            res = pdPASS;
        }
    }
    else
    {
        gaoz_osi_log( (const char *)log_debug_msg_s.pData );  
    }
#else
    gaoz_osi_log( (const char *)log_debug_msg_s.pData );
    if( log_parse_error_code( log_debug_msg_s.pData , log_debug_msg_s.DataLen , &err_code ) == pdPASS )
    {
        log_error_code_list_write( err_code );
    }
#endif
    if(osR != 0)
    {
        gaoz_mutex_unlock( log_info_mutex );
    }
    return (res);
}
    
/** ****************************************************************************
* @remarks       uint32_t log_debug_printf(log_print_mode_enum mode,char *name,const char *s, ...)
* @brief         添加系统日志打印消息头
* @param[in]     mode 打印日志的模式
* @param[in]     * name 打印日志的任务名称
* @param[in]     *s 打印日志的目标地址
* @param[in]     ... 输入参数
* @param[out]    无
* @return        pdPASS 数据发送成功 ， pdFAIL 数据发送失败
* @attention     函数的功能是将打印的数据前装到消息队列中，发送发送给任务进行数据发送
*******************************************************************************/
uint32_t log_debug_printf(log_print_mode_enum mode,char *name,const char *s, ...)
{
    uint32_t  osR = 0;
    uint32_t  res = pdFAIL;
    uint8_t   head_len = 0;
    va_list ap;
    uint32_t len;
    uint16_t err_code;

    if( log_info_mutex != 0 )
    {
        gaoz_mutex_lock( log_info_mutex );
        osR = 1;
    }
    /*清空日志缓存空间数据*/
    memset( log_debug_msg_s.pData , 0x00 ,DEBUG_UART_TX_QUEUE_LEN );
    if( mode != DEFAULE_MODE )
    {
        head_len = log_debug_head_infor( mode , name );
    }
    va_start(ap, s);
    len = vsprintf((char*)&log_debug_msg_s.pData[head_len], s, ap);
    va_end(ap);
    if( len > ( DEBUG_UART_TX_QUEUE_LEN - head_len ) )
    {
        len = DEBUG_UART_TX_QUEUE_LEN - head_len;
    }
    log_debug_msg_s.DataLen  = len + head_len;
#if( LOG_TASK_ENABLE == 1 )
    if( log_debug_queue != 0 )
    {
        res = gaoz_queue_put(log_debug_queue,&log_debug_msg_s,DEBUG_UART_TX_DATA_TIME);
        if( res == 0 )
        {
            res = pdPASS;
        } 
    }
    else
    {
        gaoz_osi_log( (const char *)log_debug_msg_s.pData );  
    }
#else
    gaoz_osi_log( (const char *)log_debug_msg_s.pData );
    if( log_parse_error_code( log_debug_msg_s.pData , log_debug_msg_s.DataLen , &err_code ) == pdPASS )
    {
        if( log_error_code_list_write( err_code ) == pdPASS )
        {
            
        }
    }
#endif
    if(osR != 0)
    {
        gaoz_mutex_unlock( log_info_mutex );
    }
    return (res);
}

/** ****************************************************************************
* @remarks       static uint16_t log_parse_error_code( uint8_t *data , uint16_t len )
* @brief         解析系统错误码
* @param[in]     *data 数据源地址
* @param[in]     len 数据长度
* @param[out]    *err 错误码地址
* @return        pdPASS 数据发送成功 ， pdFAIL 数据发送失败
* @attention     无
*******************************************************************************/
static uint32_t log_parse_error_code( uint8_t *data , uint16_t len ,uint16_t *err )
{
    uint32_t  ret = pdFAIL;
    char *log_p = NULL;
    
    log_p = strnstr(( const char* )data ,"[ERROR]" ,len );
    if( log_p != NULL )
    {
        log_p = strnstr(( const char* )log_p ,"ERRID" ,len );
        if( log_p != NULL )
        {   
            if( log_p[5] == ':' )
            {
                *err = atoi((const char *)&log_p[6]);
                if(( *err > 0  ) && ( *err < SYS_ERR_LIST_NUM ))
                {
                    ret = pdPASS;
                }
            }
        }
    }
    
    return ret;
}

/** ****************************************************************************
* @remarks       static void log_error_code_list_write( uint16_t err )
* @brief         写系统错误日志代码
* @param[in]     err 错误代码
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static uint32_t log_error_code_list_write( uint16_t err )
{
    uint32_t ret = pdFAIL, osR = 0;
    
    if(( err == 0 ) || ( err >=  SYS_ERR_LIST_NUM ))
    {
        return pdFAIL;
    }
    
    if( log_error_code.num >= SYS_ERR_LIST_NUM )
    {
        return pdFAIL;
    }
    
    if( log_error_mutex != 0 )
    {
        gaoz_mutex_lock( log_error_mutex );
        osR = 1;
    }
    if( log_error_code.id[err] == 0 )
    {   
        log_error_code.id[err] = 1;
        log_error_code.time[err] = gaoz_get_systick();
        log_error_code.num ++;
        ret = pdPASS;
    }
    if(osR != 0)
    {
        gaoz_mutex_unlock( log_error_mutex );
    }
    
    return ret;
}

/** ****************************************************************************
* @remarks       uint32_t log_error_code_list_read( uint16_t *err )
* @brief         读取系统错误日志代码
* @param[in]     无
* @param[out]    *err 错误ID代码
* @return        pdPASS 读取数据成功 ， pdFAIL 读取数据失败
* @attention     无
*******************************************************************************/
uint32_t log_error_code_list_read( uint16_t *err )
{

    return 0;
}

/** ****************************************************************************
* @remarks       uint32_t log_error_code_list_len( void )
* @brief         获取取系统错误日志代码 长度
* @param[in]     无
* @param[out]    无
* @return        错误代码长度
* @attention     无
*******************************************************************************/
uint32_t log_error_code_list_len( void )
{
    return log_error_code.num;
}

/** ****************************************************************************
* @remarks       uint32_t log_error_code_list_total_read( uint8_t *err_buf )
* @brief         获取所有的故障代码
* @param[in]     无
* @param[out]    *err_buf 故障代码目标地址
* @return        错误代码长度
* @attention     无
*******************************************************************************/
uint32_t log_error_code_list_total_read( uint8_t *err_buf )
{
    uint32_t i = 0, err_len = 0;

    if( err_buf == NULL )
    {
        return 0;
    }
    if( log_error_code.num == 0 )
    {
        return 0;
    }
    for( i = 0; i < log_error_code.len; i++ )
    {
        if( log_error_code.id[i] == 1 )
        {
            log_error_code.id[i] = 0;
            log_error_code.num --;
            err_buf[err_len] = i;
            err_len++;
        }
    }
    
    return err_len;
}

/** ****************************************************************************
* @remarks       void log_error_code_flash_write( void )
* @brief         系统错误日志代码写入FLASH 中
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void log_error_code_flash_write( void )
{
    sfb_buf_store_infor_s infor = { 0 };

    infor.infor_len = log_error_code.len;
    infor.infor_p = log_error_code.id;
    infor.infor_crc = CRC_INIT;
    sfb_write_par_store( SF_ERROE_DATA_ADDR , &infor );
}

/** ****************************************************************************
* @remarks       void log_error_code_flash_read( void )
* @brief         读取FLASH中的错误代码
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void log_error_code_flash_read( void )
{
    sfb_buf_store_infor_s infor = { 0 };
    
    infor.infor_len = log_error_code.len;
    infor.infor_p = log_error_code.id;
    infor.infor_crc = CRC_INIT;
    if( sfb_read_par_store( SF_ERROE_DATA_ADDR , &infor ) == 0 )
    {
        memset( (uint8_t *)log_error_code.id , 0x00, log_error_code.len );
    }
}

/*******************************************************************************
* 函数名称 ：void  sys_log_task( void * pvParameters)
* 函数功能 ：系统打印数据任务
* 参    数 ：无
* 返 回 值 ：无
* 说    明 ：无
*******************************************************************************/
static void  sys_log_task( void * pvParameters)
{ 
    ( void ) pvParameters;
#if( LOG_TASK_ENABLE == 1 )
    debug_msg_typedef debug_msg;
    uint16_t err_code = 0;
#endif
    mon_reg_task_dog( 60 * GAOZ_TICK_PERIOD_S ,(uint8_t * )LOG_TASK_NAME , TASK_SEM_YES );
    log_debug_send(DEBUG_MODE,LOG_TASK_NAME ,"LOG manage task started successfully\r\n",0);
    for( ;; )
    {
        mon_reset_task_dog();
    #if( LOG_TASK_ENABLE == 1 )
        if( log_queue_get(&debug_msg) == 1 )                     /*判断接收到串口打印的数据*/
        {   
            if((debug_msg.pData != NULL)&&(debug_msg.DataLen != 0))
            {   
                gaoz_osi_log( (const char *)debug_msg.pData );   /*调用系统答应接口*/
                if( log_parse_error_code(   debug_msg.pData , debug_msg.DataLen , &err_code ) == pdPASS )
                {
                    log_error_code_list_write( err_code );
                }
            }
        }
    #else
        gaoz_task_sleep( MSG_LOG_SAM_REV_WAIT_TIME );
    #endif
    }
}

